/*
 * Copyright 2003-2005 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

#include "TypeMeta.h"

#include "MetaAbstract.h"

#include "../common/BigEndianUnsignedShort.h"

type_name meta_abstract_name = { "meta.abstract" };

int meta_abstract_bind( type_element * element, type_definition * definition )
{
	int rc;
	
	rc = type_object_bind( &element->object, definition->library, &meta_abstract_name );
	if ( rc != TYPE_OK ) return rc;

	rc = type_element_bind( element, definition );
	if ( rc != TYPE_OK ) return rc;
	
	return TYPE_OK;
}

void meta_abstract_init( meta_abstract * ma )
{
	type_element_init( &(ma->expression.element), &meta_abstract_bind );
	meta_expression_init( &(ma->expression), &meta_abstract_do_read, &meta_abstract_do_write );
	intmap_init( &(ma->concreteToMap), 3);
}

void meta_abstract_create( meta_abstract * ma, int systemid )
{
	intmap_init( &(ma->concreteToMap), 3);
}

void meta_abstract_destroy( meta_abstract * ma )
{
	intmap_clear( &(ma->concreteToMap) );
}

void meta_abstract_add_map( meta_abstract * ma, int concreteId, int mapId )
{
	intmap_add( &(ma->concreteToMap), concreteId, mapId );
}

int meta_abstract_is_mapped( meta_abstract * ma, int id )
{
	return (intmap_find_value( &(ma->concreteToMap), id )>0)?false:true;
}

int meta_abstract_read( type_input_stream * in, type_element * element)
{
	meta_abstract * ma = (meta_abstract *) type_malloc( sizeof( meta_abstract ) );
	meta_abstract_init( ma );
	type_stack_set_ptr( type_input_stack( in ), element, ma );
	return TYPE_OK;
}


int meta_abstract_write( type_output_stream * out, void * o, type_element * element )
{
	// abstract is empty.  Write nothing.
	return TYPE_OK;
}


int meta_abstract_do_read( type_input_stream * in, type_element * element )
{
	meta_abstract * ma = (meta_abstract *) element;
	type_map * map = type_input_type_map( in );
	
    type_input_read_named_object( in, &uint16_name );
    uint16_t type = type_stack_get_u16( &in->stack );
    
    int mapId = type_map_get_library_id( map, type );
    
	int concrete = intmap_find_key_value( &(ma->concreteToMap) , mapId );
    if ( concrete < 0 )
    {
    	type_input_set_error( in, 10 );
    	return TYPE_EOF;
    }
	return type_input_read_object( in, type_map_get_mapped_id( map, concrete ) );
}


int meta_abstract_do_write( type_output_stream * out, void * o, type_element * element )
{
	type_object * object = (type_object *) o;
	meta_abstract * ma = (meta_abstract *) element;
	int rc;
	int id = object->definition->id;
	
	int mapId = intmap_find_value( &(ma->concreteToMap), id );
	if ( rc <= NOTYPE ) return rc;
		
	int externalId = type_map_get_mapped_id( out->map, mapId );
	if ( externalId <= NOTYPE ) return externalId;
	
	
	rc = type_output_write_named_object( out, &uint16_name, &externalId );
	if ( rc != TYPE_OK ) return rc;
	
	rc = type_map_get_mapped_id( out->map, mapId );
	if ( rc <= NOTYPE ) return rc;
	
	return type_output_write_object( out, type_map_get_mapped_id( out->map, id ), o );
}

void * meta_abstract_construct( type_library * library, void ** objects, int size )
{	
	/* FIX ME */
	return 0;
}
